foitzik.dev // my collection of random things and thoughts

SHORTY OpenPolicyAgent include

I am back to working with and exploring OPA openpolicyagent.org again.

This piece is going to seem like a rant, but I really enjoy OPA and I am grateful for the project. So I invite you to not take the rant part too serious.


One interesting part, and I see this with a lot of documentation is the following https://www.openpolicyagent.org/docs/policy-language#modules states that:

In Rego, policies are defined inside modules. Modules consist of:

  • Exactly one package declaration.
  • Zero or more import statements.
  • Zero or more rule definitions.

Modules are typically represented in Unicode text and encoded in UTF-8.

Yet fails to mention what a module is in practical terms. Is it a file? Is it all files in a directory? To my knowledge it is not mentioned there. Checking out the source code gives us a hint: It is most likely a file. Why am I mentioning this? Because around using import there is even more vagueness.

You can import "things" from "packages". But we did not know yet what a package is by not knowing what a module is, which is the super category of the package. Therefore where and how do I put something to import it? The answer is easy. Let's say you have a sample.rego and next to it a dir called other/ and in other you have sample.rego which has the package "header" package other.sample, you just use import data.other.sample. You have one or more .json files in that directory? Import them with import data.other . If you are now wondering why we did not specify the json file name - well it imports and merges all the JSON files and if it cannot merge it you will see an error on loading the bundle (oh wait I did not introduce what a bundle is yet..., yet another concept). Is that in the documentation? Maybe, but I did not see it and it was very confusing.

So effectively how imports roughly work based on my experience and understanding (very inaccurate):

The gist seems to be. No matter where you actually place a .rego file, if it contains a package directive, it get's added to that package and ignores it's physical file location inside the bundle. Subdirectories are however somehow treated as packages indirectly/directly and .json data inside them is treated as homogeneous data block and if it fails to be interpreted as homogeneous you get an error.

These are a lot of confusing elements to me, which I would have loved if they had been addressed more upfront in the documentation. Because the documentation usually assumes everything has already been loaded into memory. Which does not help build a good mental model of how to structure/author the physical files. Because if there is no adherences to file-structure, you might end up "missplacing" a .rego file and your bundle still works correctly even if it's in some different folder.

As an outlook, I am going to re-read the docs and probably going to submit a PR if I can find the time to do so, adding the suggestions I made earlier.